/********************************************************************************
* Copyright ------
*
* ソース名:
*　　CppResult.c
*
* 機能:
*　　展開後のソース行を記録する
*
* 作成者:
*　　2010/05 関（CBSﾃｸﾉ）

********************************************************************************
変更履歴:
　新規　　　展開後のソース行を対応するため
*******************************************************************************/

#include "../coredef.h"
#include "cppdef.h"

#define MAX_EMPTY_LINE 5
static  HFILE	hCppResultFile;
static  AST  currFileIndex = 0;
static  U4 	currLineNum = 0;
static  U2  preOffset = 0;
static  char cppResultFileName[OS_FULLPATH+4];
static  char tempBuf[OS_FULLPATH+4];
static  char tempBuf2[OS_FULLPATH+4];
/* 統一内部関数 */

/*D */
static U4   cppResultOffsetSize( AST astPhyScp, U4 ulResultOffSet )
{
	U4 ulOffsetSize = 0;
	U2 usOffset = 0;

	usOffset = stCoreCodeScpAccess.startOffset.get( astPhyScp );

	if( usOffset < preOffset ){
		ulOffsetSize = 0;
	}else{
		ulOffsetSize = usOffset - preOffset;
	}
	preOffset = stCoreCodeScpAccess.endOffset.get( astPhyScp );

	return ulOffsetSize+ulResultOffSet;
}
static S4 cppResultOutputLineDirective( AST astPhyScope )
{
	AST astFileIndex;
	S4  s4PhyLineNum;
	S4 nRet;
	PSZ pszBuf;
	PSZ pszFile;
	U4 pathLen;

	astFileIndex = stCoreCodeScpAccess.fileindex.get( astPhyScope );
	s4PhyLineNum = stCoreCodeScpAccess.startLine.get( astPhyScope );
	if( currFileIndex != 0 || currLineNum != 0 )
	{
		nRet = FileWrite(hCppResultFile, "\n", 1 );
		if( nRet != COEXIT_SUCCESS )
		{
			return (nRet);
		}
	}
	nRet = FileWrite(hCppResultFile, "#line", 5 );
	if( nRet != COEXIT_SUCCESS )
	{
		return (nRet);
	}
	sprintf( tempBuf, " %ld ", s4PhyLineNum );
	nRet = FileWrite(hCppResultFile, tempBuf , strlen(tempBuf) );
	if( nRet != COEXIT_SUCCESS )
	{
		return (nRet);
	}
	pszBuf = tempBuf;
	*pszBuf = '\"';
	pszBuf++;
	pathLen = stCoreFileIndexAccess.getFile(astFileIndex,tempBuf2, OS_FULLPATH );
	if( pathLen == 0 || pathLen > OS_FULLPATH ){
		return COEXIT_FATAL;
	}
	pszFile = tempBuf2;
	while( *pszFile != '\0' ){
		if( *pszFile == '\\' ){
			*pszBuf = '\\';
			pszBuf++;
			*pszBuf = '\\';
			pszBuf++;
		}else{
			*pszBuf = *pszFile;
			pszBuf++;
		}
		pszFile++;
	}
	*pszBuf = '\"';
	pszBuf++;
	*pszBuf = '\0';
	nRet = FileWrite(hCppResultFile, tempBuf , strlen(tempBuf) );
	if( nRet != COEXIT_SUCCESS )
	{
		return (nRet);
	}
	nRet = FileWrite(hCppResultFile, "\n" , 1 );
	if( nRet != COEXIT_SUCCESS )
	{
		return (nRet);
	}
	currFileIndex = astFileIndex;
	currLineNum = s4PhyLineNum;
	return COEXIT_SUCCESS;
}
/************************************************************************
 * 関 数 名 : 	CppResultInit
 * 機 　  能 :	初期化する
 * 　仕様：　　　各データを初期化し、CPPの結果ファイルを作成する。
 * 引 き 数 : 	cFilename		Cソースファイル名
 * 戻 り 値 :	成功　：COEXIT_SUCCESS
 * 			失敗　：COEXIT_FATAL
************************************************************************/
S4		CppResultInit( PSZ pszSrc, PSZ pszOut )
{
	if( pszOut != NULL ){
		strcpy( cppResultFileName, pszOut );
	}else{
		if( NULL == Convert2CppResultFile( pszSrc, cppResultFileName ) )
		{
			return ( COEXIT_FATAL );
		}
	}
	hCppResultFile = 0;
	currFileIndex = 0;
	currLineNum = 0;
	if( hCppResultFile != 0 )
	{
		FileClose( hCppResultFile );
	}
	if( COEXIT_SUCCESS != FileOpen( cppResultFileName, FLMOD_WRITEONLY, &hCppResultFile) )
	{
		return (COEXIT_FATAL);
	}
	return COEXIT_SUCCESS;
}
/************************************************************************
 * 関 数 名 : 	CppResultTerminal
 * 機 　  能 :	終了する
 * 　仕様：　　　ファイルをクローズする
 * 引 き 数 : 	NULL
 * 戻 り 値 :	成功　：COEXIT_SUCCESS
 * 			失敗　：COEXIT_FATAL
************************************************************************/
S4		CppResultTerminal( VOID )
{
	if( COEXIT_SUCCESS != FileClose( hCppResultFile ) )
	{
		return (COEXIT_FATAL);
	}
	currLineNum = 0;
	currFileIndex = 0;
	hCppResultFile = 0;
	cppResultFileName[0]='\0';
	return COEXIT_SUCCESS;
}
/************************************************************************
 * 関 数 名 : 	CppResultOutput
 * 機 　  能 :	前処理結果を出力する
 * 　仕様：　　　KIND_PPTOKENLISTを出力する。astStart～最後
 * 引 き 数 : 	astStart　前処理字句の起点
 * 　　　　　　　　bMacroCall　マクロ有無フラグ
 * 戻 り 値 :	成功　：COEXIT_SUCCESS
 * 			失敗　：COEXIT_FATAL
************************************************************************/
S4		CppResultOutput( AST  astStart, BOOL  bMacroCall )
{
	AST astFileIndex;
	AST    astEnd = 0;
	AST    astCnt = 0;
	AST    astPhyScope = 0;
	S4    s4PhyLineNum = 0;
	S4		nRet;

	PSZ		pszTokenName;
	U4   ulResultOffSet = 0;
	U4   ulBeginOffSet = 0;



	astEnd = stCorePPTokenListAccess.getMax();
	astCnt = astStart;

	if( astCnt > astEnd )
	{
		return COEXIT_SUCCESS;
	}
	for( ; astCnt <= astEnd; astCnt++ )
	{
		pszTokenName = stCorePPTokenListAccess.name.get( astCnt ) ;
		astPhyScope = stCorePPTokenListAccess.codeScope.get( astCnt );

		astFileIndex = stCoreCodeScpAccess.fileindex.get( astPhyScope );
		s4PhyLineNum = stCoreCodeScpAccess.startLine.get( astPhyScope );
		if( astFileIndex != currFileIndex ){
			nRet = cppResultOutputLineDirective(astPhyScope);
			if( nRet != COEXIT_SUCCESS )
			{
				return (nRet);
			}
			currLineNum = s4PhyLineNum;
			ulResultOffSet = 0;
			preOffset = 0;
		}else if( currLineNum != s4PhyLineNum )
		{
			if( s4PhyLineNum - currLineNum > MAX_EMPTY_LINE  ){
				nRet = cppResultOutputLineDirective(astPhyScope);
				if( nRet != COEXIT_SUCCESS )
				{
					return (nRet);
				}
				currLineNum = s4PhyLineNum;
			}else{
				while( currLineNum < s4PhyLineNum  ){
					nRet = FileWrite(hCppResultFile, "\n", 1 );
					if( nRet != COEXIT_SUCCESS )
					{
						return (nRet);
					}
					currLineNum++;
				}
			}
			ulResultOffSet = 0;
			preOffset = 0;
		}
		if( pszTokenName != NULL )
		{
			ulBeginOffSet = cppResultOffsetSize( astPhyScope, ulResultOffSet );
			for( ; ulResultOffSet < ulBeginOffSet; ulResultOffSet++ )
			{
				nRet = FileWrite(hCppResultFile, " ", 1 );
				if( nRet != COEXIT_SUCCESS )
				{
					return (nRet);
				}
			}
			nRet = FileWrite(hCppResultFile, pszTokenName, strlen(pszTokenName) );
			if( nRet != COEXIT_SUCCESS )
			{
				return (nRet);
			}
			ulResultOffSet += strlen(pszTokenName);
		}
	}
	return COEXIT_SUCCESS;
}
/************************************************************************
 * 関 数 名 : 	Convert2CppResultFile
 * 機 　  能 :	Cソースのパス名から該当するプリプロ結果ファイルのパス名を作成する
 * 　　　　　　　　　引数の何れかはNULLである場合、失敗
 * 　　　　　　　　　2つの引数は等しい場合、　失敗（Cソースパスは上書きされないように）
 * 　　　　　　　　　Cソースのパス名は空文字列の場合、失敗
 *
 * 　仕様：　　　　Cソースの最後の文字を　英字[i]に変更する。
 * 引 き 数 : 	cFilename		Cソースファイル名
 *          cppFilename     プリプロ結果ファイルのパス名を保存するバッファー
 * 戻 り 値 :	成功　：プリプロ結果ファイルのパス名を返す
 * 			失敗　：NULL
************************************************************************/
CHAR * DLL_EXPORT Convert2CppResultFile( CHAR * cFilename, CHAR * cppFilename )
{
	INT nLen = 0;
	if( cFilename==NULL || cppFilename==NULL || cFilename==cppFilename )
	{
		return NULL;
	}
	if(strlen(cFilename)>0)
	{
		nLen = (strlen(cFilename)<OS_FULLPATH)?strlen(cFilename):(OS_FULLPATH-1);
		strncpy( cppFilename, cFilename, nLen );
		cppFilename[nLen-1]='i';
		cppFilename[nLen] = '\0';
		return( cppFilename );
	}
	return( NULL );
}
EXTERNAL_SYMBOL( Convert2CppResultFile );

/* end of file */

